package com.automation.ljf.service.impl;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

import com.automation.ljf.converter.CaseConvert;
import com.automation.ljf.converter.CaseReportConvert;
import com.automation.ljf.converter.CaseStepConvert;
import com.automation.ljf.domain.dataobject.CaseStepReportDO;
import com.automation.ljf.repository.TestCaseRepository;
import com.automation.ljf.service.TestUseCaseService;
import com.automation.ljf.strategy.context.OperationStrategyContext;
import com.automation.ljf.util.CommonUtil;
import org.openqa.selenium.chrome.ChromeDriver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.github.pagehelper.PageHelper;
import com.automation.ljf.domain.dataobject.CaseDO;
import com.automation.ljf.domain.dataobject.CaseReportDO;
import com.automation.ljf.domain.dataobject.CaseStepDO;
import com.automation.ljf.domain.request.CaseRequest;
import com.automation.ljf.domain.request.CaseStepRequest;
import com.automation.ljf.domain.vo.CaseReportVO;
import com.automation.ljf.domain.vo.CaseStepVO;
import com.automation.ljf.domain.vo.CaseVO;
import com.automation.ljf.util.DriverUtils;
import com.automation.ljf.util.ResultMessage;

import lombok.extern.slf4j.Slf4j;

/**
 * 用户基础操作业务层
 *
 * @author lijiefeng
 * @since 2021/8/25
 */
@Service
@Slf4j
public class TestCaseServiceImpl implements TestUseCaseService {

    @Autowired
    private TestCaseRepository testCaseRepository;

    @Autowired
    private OperationStrategyContext strategyContext;

    @Autowired
    private CaseStepConvert caseStepConvert;

    @Autowired
    private CaseConvert caseConvert;

    @Autowired
    private CaseReportConvert caseReportConvert;

    /**
     * 创建用例
     * @param caseRequest   用例接收参数类
     * @return  ResultMessage
     */
    @Override
    public ResultMessage createCase(CaseRequest caseRequest) {

        CaseDO caseDO = caseConvert.caseRequestToCaseDO(caseRequest);
        int res = testCaseRepository.insertCase(caseDO);
        return res > 0 ? ResultMessage.ok("创建成功") : ResultMessage.error("创建失败");
    }

    /**
     * 添加用例步骤
     * @param caseStepRequest   用例步骤实体
     * @return  R
     */
    @Override
    public ResultMessage createCaseStep(CaseStepRequest caseStepRequest) {
        CaseStepDO caseStepDO = caseStepConvert.caseStepRequestToDO(caseStepRequest);
        int res = testCaseRepository.insertCaseStep(caseStepDO);
        return res > 0 ? ResultMessage.ok("添加成功") : ResultMessage.error("添加失败");
    }

    /**
     * 根据用户id查询用户创建的用例
     * @param admUserId 用户id
     * @param page  当前页数
     * @param limit 每页数量
     * @return  R
     */
    @Override
    public ResultMessage selectCaseByUId(String admUserId, Integer page, Integer limit) {

        return testCaseRepository.selectCaseByPage(admUserId, page, limit);

    }

    /**
     * 根据用例id查询用例详情
     * @param caseId    用例id
     * @return  R
     */
    @Override
    public ResultMessage selectCaseByCaseId(String caseId) {
        //查询测试用例是否存在
        CaseVO caseVO = testCaseRepository.selectCaseByCaseId(caseId);
        if (caseVO == null){
            return ResultMessage.error("不存在该测试用例");
        }
        return ResultMessage.ok("查询成功").addData("caseVO", caseVO);

    }

    /**
     * 执行测试用例
     * @param caseId    用例id
     * @param jsonData  json对象
     * @return  R
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage ExecuteCaseByCaseId(String caseId, String jsonData) {

        //根据测试用例id获取测试用例
        ResultMessage caseR = selectCaseByCaseId(caseId);
        if (caseR.getCode() == 102){
            return caseR;
        }
        CaseVO caseVO = (CaseVO) caseR.getData().get("caseVO");
        CaseDO caseDO = caseConvert.caseVOToDO(caseVO);
        //获取当前测试用例的所有用例步骤  type:DO
        ResultMessage stepR = testCaseRepository.selectCaseStepByCId(caseId);
        List<CaseStepDO> caseStepDOS = (List<CaseStepDO>) stepR.getData().get("caseStepDOS");
        if (caseStepDOS.size() == 0){
            return ResultMessage.error("该测试用例没有步骤，无法执行。");
        }
        //生成当前测试用例的记录id
        String reportId = CommonUtil.generateOID();
        //执行测试用例核心代码
        List<CaseStepReportDO> caseStepReportDOS = doBusiness(caseDO, caseStepDOS, jsonData, reportId);
        if (caseStepReportDOS == null){
            return ResultMessage.error("用例步骤执行出现异常");
        }
        //将执行成功用例和该用例步骤存到对应的report表
        CaseReportDO caseReportDO = caseConvert.caseDOToCaseReportDO(caseDO);
        caseReportDO.setCaseResult(true);
        int caseReportNum = testCaseRepository.insertCaseReport(caseReportDO, reportId);
        log.info("插入了" + caseReportNum + "条数据到case_report表");
        int stepReportNum = testCaseRepository.insertCaseStepReport(caseStepReportDOS, reportId);
        log.info("插入了" + stepReportNum + "条数据到case_step_report表中");
        return ResultMessage.ok("执行用例完成");
    }

    /**
     * 根据用例id查询用例所有步骤
     * @param caseId    用例id
     * @return  ResultMessage
     */
    @Override
    public ResultMessage selectStepByCaseId(String caseId, Integer page, Integer limit) {
        if (page != null && limit != null){
            //进行分页
            PageHelper.startPage(page, limit);
        }
        ResultMessage stepR = testCaseRepository.selectCaseStepByCId(caseId);
        List<CaseStepDO> caseStepDOS = (List<CaseStepDO>) stepR.getData().get("caseStepDOS");
        List<CaseStepVO> caseStepVOS = caseStepDOS.stream().map(caseStepConvert::caseStepDOToVO)
                .sorted(Comparator.comparing(CaseStepVO::getStepId))
                .collect(Collectors.toList());

        return caseStepVOS.size() > 0 ?
                ResultMessage.ok("查询成功")
                        .addData("caseStepVOS", caseStepVOS)
                        .addData("total", stepR.getData().get("total")) : ResultMessage.error("没有数据").addData("total", stepR.getData().get("total"));
    }

    /**
     * 查询用例是否存在需要输入的步骤
     * @param caseId    用例id
     * @return  R
     */
    @Override
    public ResultMessage selectStepIsInputByCaseId(String caseId) {
        int size = testCaseRepository.selectStepIsInputByCaseId(caseId);
        return ResultMessage.ok("查询数量成功").addData("size", size);
    }

    /**
     * 查询当前用户的用例结果集
     * @return R
     */
    @Override
    public ResultMessage selectCaseReportByUId(String admUserId, Integer page, Integer limit) {
        PageHelper.startPage(page, limit);
        ResultMessage caseReportR = testCaseRepository.selectCaseReportByUId(admUserId);
        List<CaseReportDO> caseReportDOS = (List<CaseReportDO>) caseReportR.getData().get("caseReportDOS");
        List<CaseReportVO> caseReportVOS = caseReportDOS.stream()
                .map(caseReportConvert::caseReportDOToVO)
                .collect(Collectors.toList());
        return caseReportVOS.size() > 0 ?
                ResultMessage.ok("查询成功")
                        .addData("caseReportVOS", caseReportVOS)
                        .addData("total", caseReportR.getData().get("total")) :
                ResultMessage.error("没有数据").addData("total", caseReportR.getData().get("total"));
    }

    @Override
    public ResultMessage selectStepReportByCaseReportId(String reportId, Integer page, Integer limit) {
        PageHelper.startPage(page, limit);
        return testCaseRepository.selectStepReportByCaseReportId(reportId);
    }

    @Override
    public ResultMessage updateCaseByCaseId(CaseRequest caseRequest) {
        CaseDO caseDO = caseConvert.caseRequestToCaseDO(caseRequest);
        int res = testCaseRepository.updateCaseByCaseId(caseDO);
        return res > 0 ? ResultMessage.ok("修改成功") : ResultMessage.error("修改失败");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResultMessage deleteCaseByCaseId(List<CaseRequest> caseRequestList) {
        List<CaseDO> caseDOS = caseRequestList.parallelStream().map(caseConvert::caseRequestToCaseDO).collect(Collectors.toList());
        int res = testCaseRepository.deleteCaseByCaseId(caseDOS);
        return res == caseDOS.size() ? ResultMessage.ok("删除成功") : ResultMessage.error("删除失败");
    }

    @Override
    public ResultMessage deleteStepByCaseId(String caseId, List<CaseStepRequest> caseStepRequests) {
        List<CaseStepDO> caseStepDOS = caseStepRequests.parallelStream()
                .map(caseStepConvert::caseStepRequestToDO).collect(Collectors.toList());
        int res = testCaseRepository.deleteStepByCaseId(caseId, caseStepDOS);
        return res == caseStepDOS.size() ? ResultMessage.ok("删除成功") : ResultMessage.error("删除失败");
    }

    /**
     * 执行用例步骤业务
     * @param caseDO    用例实体DO
     * @param caseStepDOS   用例步骤实体DO集合
     * @param jsonData  用例步骤操作传参
     * @param reportId  用例步骤记录id
     * @return  List<CaseStepReportDO>
     */
    public List<CaseStepReportDO> doBusiness(CaseDO caseDO,
                                             List<CaseStepDO> caseStepDOS,
                                             String jsonData,
                                             String reportId){
        //存放已经执行的步骤
        List<CaseStepReportDO> caseStepReportDOS = new ArrayList<>();
        //打开测试网页并设置网页参数,返回chromedriver
        ChromeDriver driver = DriverUtils.setUrlPage(caseDO);
        //存放window窗口句柄
        String[] windows = new String[caseStepDOS.size()+1];


        String windowId = null;
        //根据操作类型，执行用例每一步操作
        for (CaseStepDO caseStepDO : caseStepDOS) {
            //如果当前操作是切换窗口操作
            if (caseStepDO.getStepOperation().equals("SWITCH_WINDOW")){
                windowId = windows[caseStepDO.getStepRelation()];
            }
            //执行策略操作，返回stepR
            ResultMessage stepR = null;
            if (windowId != null){
                //切换窗口操作，传过去的应该是切换的窗口句柄id
                stepR = strategyContext.getResource(caseStepDO)
                        .doOperation(driver, caseStepDO, windowId);
            }else{
                //其它正常操作
                stepR = strategyContext.getResource(caseStepDO)
                        .doOperation(driver, caseStepDO, jsonData);
            }
            //实体转换
            CaseStepReportDO caseStepReportDO = caseStepConvert.caseStepDOToCaseStepReportDO(caseStepDO);
            //获取本次操作输入的值
            String parameter = (String) stepR.getData().get("parameter");
            if (parameter != null){
                caseStepReportDO.setStepParameter(parameter);
            }
            //获取本次操作所在的窗口的句柄
            String window = (String) stepR.getData().get("window");
            if (window != null){
                caseStepReportDO.setStepWindow(window);
                //存进数组里，用于做窗口切换操作
                windows[caseStepReportDO.getStepId() - 1] = window;
            }
            //如果当前操作步骤出现异常
            if (stepR.getCode() == 400){
                driver.quit(); //关闭浏览器driver
                log.error("步骤执行出现异常：\n" + stepR.getMessage());
                String errorMsg = (String) stepR.getData().get("errorMsg");
                //将当前测试用例添加到mf_case_report表
                CaseReportDO caseReportDO = caseConvert.caseDOToCaseReportDO(caseDO);
                caseReportDO.setCaseResult(false);
                int caseReportNum = testCaseRepository.insertCaseReport(caseReportDO, reportId);
                log.info("插入了" + caseReportNum + "条数据到case_report表");

                caseStepReportDO.setActualResult("FALSE")
                        .setStepResDetail(errorMsg);
                caseStepReportDOS.add(caseStepReportDO);
                //将执行异常的用例添加到mf_case_step_report表
                int stepReportNum = testCaseRepository.insertCaseStepReport(caseStepReportDOS, reportId);
                log.info("插入了" + stepReportNum + "条数据到case_step_report表中");
                return null;
            }else{
                //当前步骤执行成功
                caseStepReportDO.setActualResult("TRUE");
                //判断获取文本值操作是否有返回content
                String content = (String) stepR.getData().get("content");
                if (content != null){
                    caseStepReportDO.setActualResult(content);
                }

            }
            caseStepReportDOS.add(caseStepReportDO);
        }
        driver.quit();
        return  caseStepReportDOS;
    }

}
